package com.coocaa.ops.api.v1.content.service.internal;

import com.coocaa.ops.api.base.third.dmp.IDmpService;
import com.coocaa.ops.api.common.model.HeaderModel;
import com.coocaa.ops.api.v1.content.cache.IPanelInfoCache;
import com.coocaa.ops.api.v1.content.cache.ITabInfoCache;
import com.coocaa.ops.api.v1.content.model.internal.PanelContentInfo;
import com.coocaa.ops.api.v1.content.model.internal.PanelSimpleInfo;
import com.coocaa.ops.api.v1.content.model.internal.PanelSimpleInfoWithDmp;
import com.coocaa.ops.api.v1.content.model.query.PanelQueryModel;
import com.coocaa.ops.common.core.biz.dmp.entity.DmpRegistryRlsInfoEntity;
import com.coocaa.ops.common.core.biz.panel.entity.BlockContentConfigInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author tangminghong
 * @date 2020-09-03
 */
@Service
public class DmpTabPanelService {

    @Autowired
    private ITabInfoCache tabInfoCache;

    @Autowired
    private IPanelInfoCache panelInfoCache;
    @Autowired
    private IDmpService dmpService;

    public List<PanelSimpleInfo> handlePanelDmp(List<PanelSimpleInfo> panelList, PanelQueryModel queryModel) {
        List<PanelSimpleInfoWithDmp> dmpPanelList = panelInfoCache.getAllDmpPanels(queryModel.getTabId(), queryModel.getPolicyCategory());
        Map<Integer, PanelSimpleInfo> dmpPanelSeqMap = matchAndGetDmpPanelBySeq(dmpPanelList, queryModel.getHeader());
        return getFinalPanelList(panelList, dmpPanelSeqMap);
    }

    public void handleBlockDmp(PanelContentInfo panelContent, PanelQueryModel queryModel, boolean groupPanel) {
        List<BlockContentConfigInfo> dmpBlockList = panelInfoCache.getAllDmpBlocks(panelContent.getId(), panelContent.getCurrentVersion(), queryModel.getPolicyCategory(), groupPanel);

        Map<Integer, BlockContentConfigInfo> dmpBlockSeqMap = matchAndGetDmpBlockBySeq(dmpBlockList, queryModel.getHeader());
        panelContent.setBlockContentList(getFinalBlockList(panelContent.getBlockContentList(), dmpBlockSeqMap));
    }

    /*********************板块dmp相关私有方法***************************/

    private Set<Integer> getPanelAllPolicyId(List<PanelSimpleInfoWithDmp> dmpPanelList) {
        if (CollectionUtils.isEmpty(dmpPanelList)) {
            return Collections.emptySet();
        }
        Set<Integer> result = new HashSet<>();
        for (PanelSimpleInfoWithDmp dmpPanel : dmpPanelList) {
            DmpRegistryRlsInfoEntity dmpInfo = dmpPanel.getDmpRegistryInfo();
            if (dmpInfo != null) {
                result.add(dmpInfo.getDmpPolicyId());
            }
        }
        return result;
    }

    private Map<Integer, PanelSimpleInfo> matchAndGetDmpPanelBySeq(List<PanelSimpleInfoWithDmp> dmpPanelList, HeaderModel header) {
        if (CollectionUtils.isEmpty(dmpPanelList)) {
            return Collections.emptyMap();
        }
        Set<Integer> policyIds = getPanelAllPolicyId(dmpPanelList);
        Set<Integer> crowdIds = getMatchedCrowdIdFromDmp(policyIds, header);

        LinkedHashMap<Integer, PanelSimpleInfo> result = new LinkedHashMap<>();
        for (PanelSimpleInfoWithDmp dmpPanel : dmpPanelList) {
            DmpRegistryRlsInfoEntity dmpInfo = dmpPanel.getDmpRegistryInfo();
            if (dmpInfo == null) {
                continue;
            }
            Integer seq = dmpInfo.getSubContainerSeq();
            dmpPanel.setSeq(seq);
            if (result.get(seq) == null && matched(dmpInfo, crowdIds)) {
                result.put(seq, dmpPanel);
            } else if (result.get(seq) != null && matched(dmpInfo, crowdIds)) {
                PanelSimpleInfoWithDmp oldDmpPanel = (PanelSimpleInfoWithDmp)result.get(seq);
                Integer contentSeq = dmpInfo.getSubContainerContentSeq();
                Integer oldContentSeq = oldDmpPanel.getDmpRegistryInfo().getSubContainerContentSeq();
                if (contentSeq < oldContentSeq) {
                    result.put(seq, dmpPanel);
                }
            }
        }
        return result;
    }

    private List<PanelSimpleInfo> getFinalPanelList(List<PanelSimpleInfo> normalPanelList, Map<Integer, PanelSimpleInfo> dmpPanelMap) {

        List<PanelSimpleInfo> finalPanelList = normalPanelList == null ? new ArrayList<>(0) : new ArrayList<>(normalPanelList);
        dmpPanelMap = dmpPanelMap == null ? Collections.emptyMap() : dmpPanelMap;

        /**
         * 逻辑：首先将普通板块列表中匹配dmp的位置替换为dmp匹配的板块，然后将剩余的dmp匹配的板块添加到末尾，最后再根据seq排序
         */
        ListIterator<PanelSimpleInfo> i = finalPanelList.listIterator();
        while (i.hasNext()) {
            PanelSimpleInfo panel = i.next();
            Integer seq = panel.getSeq();
            if (dmpPanelMap.containsKey(seq)) {
                i.set(dmpPanelMap.get(seq));
                dmpPanelMap.remove(seq);
            }
        }

        finalPanelList.addAll(dmpPanelMap.values());

        finalPanelList.sort(Comparator.comparing(PanelSimpleInfo::getSeq));


        return finalPanelList;
    }

    /*********************推荐位dmp相关私有方法***************************/

    private Map<Integer, BlockContentConfigInfo> matchAndGetDmpBlockBySeq(List<BlockContentConfigInfo> dmpBlockList, HeaderModel header) {
        if (CollectionUtils.isEmpty(dmpBlockList)) {
            return Collections.emptyMap();
        }

        Set<Integer> policyIds = getBlockAllPolicyId(dmpBlockList);
        Set<Integer> crowdIds = getMatchedCrowdIdFromDmp(policyIds, header);

        LinkedHashMap<Integer, BlockContentConfigInfo> result = new LinkedHashMap<>();
        for (BlockContentConfigInfo dmpBlock : dmpBlockList) {
            DmpRegistryRlsInfoEntity dmpInfo = dmpBlock.getDmpRegistryInfo();
            if (dmpInfo == null) {
                continue;
            }
            Integer seq = dmpInfo.getSubContainerSeq();
            dmpBlock.setBlockSeq(seq);
            if (result.get(seq) == null && matched(dmpInfo, crowdIds)) {
                result.put(seq, dmpBlock);
            } else if (result.get(seq) != null && matched(dmpInfo, crowdIds)) {
                BlockContentConfigInfo oldDmpPanel = (BlockContentConfigInfo)result.get(seq);
                Integer contentSeq = dmpInfo.getSubContainerContentSeq();
                Integer oldContentSeq = oldDmpPanel.getDmpRegistryInfo().getSubContainerContentSeq();
                if (contentSeq < oldContentSeq) {
                    result.put(seq, dmpBlock);
                }
            }
        }
        return result;
    }

    private Set<Integer> getBlockAllPolicyId(List<BlockContentConfigInfo> dmpBlockList) {
        if (CollectionUtils.isEmpty(dmpBlockList)) {
            return Collections.emptySet();
        }
        Set<Integer> result = new HashSet<>();
        for (BlockContentConfigInfo dmpBlock : dmpBlockList) {
            DmpRegistryRlsInfoEntity dmpInfo = dmpBlock.getDmpRegistryInfo();
            if (dmpInfo != null) {
                result.add(dmpInfo.getDmpPolicyId());
            }
        }
        return result;
    }

    private List<BlockContentConfigInfo> getFinalBlockList(List<BlockContentConfigInfo> normalBlockList, Map<Integer, BlockContentConfigInfo> dmpBlockMap) {

        List<BlockContentConfigInfo> finalBlockList = normalBlockList == null ? new ArrayList<>(0) : new ArrayList<>(normalBlockList);
        dmpBlockMap = dmpBlockMap == null ? Collections.emptyMap() : dmpBlockMap;

        /**
         * 逻辑：首先将普通板块列表中匹配dmp的位置替换为dmp匹配的板块，然后将剩余的dmp匹配的板块添加到末尾，最后再根据seq排序
         */
        ListIterator<BlockContentConfigInfo> i = finalBlockList.listIterator();
        while (i.hasNext()) {
            BlockContentConfigInfo panel = i.next();
            Integer seq = panel.getBlockSeq();
            if (dmpBlockMap.containsKey(seq)) {
                i.set(dmpBlockMap.get(seq));
                dmpBlockMap.remove(seq);
            }
        }

        finalBlockList.addAll(dmpBlockMap.values());

        finalBlockList.sort(Comparator.comparing(BlockContentConfigInfo::getBlockSeq));


        return finalBlockList;
    }

    /*********************公共dmp方法***************************/

    private Set<Integer> getMatchedCrowdIdFromDmp(Set<Integer> policyIds, HeaderModel header) {
        return dmpService.getMatchedCrowdIdsFromDmp(policyIds, header);
    }

    private boolean matched(DmpRegistryRlsInfoEntity dmpInfo, Set<Integer> crowdIds) {
        if (CollectionUtils.isEmpty(crowdIds)) {
            return false;
        }
        return crowdIds.contains(dmpInfo.getDmpCrowdId());
    }
}
